#include <iostream>
#include <sstream>
#include "IntermediateCode.h"

IntermediateCode::IntermediateCode()
{
	labelCounter = 0;
	applyLabel = false;
	currentTAC = 0;
}

IntermediateCode::~IntermediateCode()
{
}

bool IntermediateCode::hasNextTAC() {
	return currentTAC < iCodeRepository.size();
}

const ThreeAddressCode* IntermediateCode::nextTAC() {
	return &iCodeRepository[currentTAC++];
}

int IntermediateCode::getFunctionSize(std::string functionLabel) {
	FunctionSizeMap::iterator res = fSize.find( functionLabel );
	if(res == fSize.end()) {
		return 0;
	}
	return res->second;
}

void IntermediateCode::addTAC(ThreeAddressCode tac) {
	setLabel( tac );
	iCodeRepository.push_back(tac);
	
#if DEBUG_INT_CODE
	std::cout << tac << "\n";
#endif	
}

std::string IntermediateCode::getNextLabel() {
	std::stringstream ss;
	ss << "LABEL" << labelCounter++;
	return ss.str();
}

void IntermediateCode::threeAddressCode(attr result, OpCode opCode, int index) {
	ThreeAddressCode tac(result, index, opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(int rawAddress, OpCode opCode, std::string callLabel, int paramCount) {
	attr ra;
	ra.addr = rawAddress;
	ThreeAddressCode tac(ra, callLabel, paramCount, opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(OpCode opCode, attr operand, std::string gotoLabel) {
	ThreeAddressCode tac( operand, gotoLabel, opCode );
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(OpCode opCode, std::string label) {
	ThreeAddressCode tac(label, opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(attr destAddr, OpCode opCode, std::string label, int paramCount) {
	ThreeAddressCode tac(destAddr, label, paramCount, opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(attr destAddr, OpCode opCode, attr param1, attr param2) {
	ThreeAddressCode tac(destAddr, param1, param2, opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(OpCode opCode, attr paramAddr) {
	ThreeAddressCode tac(paramAddr, opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(OpCode opCode, ParamList* pList) {
	for(ParamList::iterator i=pList->begin();
		i!=pList->end();
		++i)
	{
		threeAddressCode(opCode, (*i)->getAttr() );
	}
}

void IntermediateCode::threeAddressCode(attr destAddr, OpCode opCode, attr operand) {
	ThreeAddressCode tac(destAddr, operand, opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(OpCode opCode) {
	ThreeAddressCode tac(opCode);
	addTAC( tac );
}

void IntermediateCode::threeAddressCode(std::string pLabel) {
	if(applyLabel) {
		ThreeAddressCode tac(TAC_NO_OP);
		addTAC( tac );
	}
	
	label = pLabel;
	applyLabel = true;
}

void IntermediateCode::setLabel(ThreeAddressCode &tac) {
	if(applyLabel) {
		applyLabel = false;
		tac.setLabel(label);
	}
}

void IntermediateCode::updateFunction(std::string funcLabel, int funcSize) {
	FSizePair fsp(funcLabel, funcSize);
	fSize.insert( fsp );
}
